package cn.tianyun.pethome.interceptor;

import cn.tianyun.pethome.annotation.PreAuthorize;
import cn.tianyun.pethome.basic.jwt.JwtUtils;
import cn.tianyun.pethome.basic.jwt.Payload;
import cn.tianyun.pethome.basic.jwt.PayloadData;
import cn.tianyun.pethome.basic.jwt.RsaUtils;
import cn.tianyun.pethome.basic.util.BaseConstants;
import cn.tianyun.pethome.org.domain.Employee;
import cn.tianyun.pethome.org.domain.Logininfo;
import cn.tianyun.pethome.org.mapper.EmployeeMapper;
import cn.tianyun.pethome.system.domain.Permission;
import cn.tianyun.pethome.system.mapper.PermissionMapper;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/*
* springMVC拦截器
* */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Value("${jwt.publickey}")
    private String publickey;
    @Value("${jwt.privatekey}")
    private String privatekey;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       try {
           String token = request.getHeader("token");
           if(token==null){
               resultError(response,"NoLogin");
              return false;
           }
           //校验token
          // Object tokenObj = redisTemplate.opsForValue().get(token) ;
           //获取解密用的公钥
           PublicKey publicKey = RsaUtils.getPublicKey(JwtUtils.class.getClassLoader().getResource(publickey).getFile());
           //获取载荷
           Payload<PayloadData> payload = JwtUtils.getInfoFromToken(token, publicKey, PayloadData.class);
           //获取载荷里面的用户信息
           PayloadData userInfo = payload.getUserInfo();
           boolean isCheck = permissionCheck(userInfo, handler);
               if(!isCheck){
                   resultError(response,"NoPermission");
                   return false;
               }
           //刷新token
           //过期时间
           Date expiration = payload.getExpiration();
           //刷新时间
           DateTime refreshTime = new DateTime(expiration).minusMinutes(5);
           //当前时间在刷新时间之后就要刷新一把
           if(refreshTime.isBefore(DateTime.now())){
               PrivateKey privateK = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader()
                       .getResource(privatekey)
                       .getFile());
               String result = JwtUtils.generateTokenExpireInSeconds(userInfo, privateK, 12*60*60);
               //重新登录刷新token          response.getWriter().write("{\"success\":false,\"message\":\"noLogin\"}");
               response.getWriter().write("{\"success\":true,\"message\":\"refresh\",\"token\":\""+result+"\"}");
               return false;
           }
               return true;
       }catch (Exception e){
           e.printStackTrace();//记录日志
           resultError(response,"NoLogin");
           return false;
       }
    }
    private boolean permissionCheck(PayloadData userInfo,Object handler) {
        //解决 handler 类型转换错误的问题   如果没有问题可以不用加上
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        //获取方法
        HandlerMethod handlerMethod= (HandlerMethod)handler;
        //获取当前请求方法的注解
        PreAuthorize methodAnnotation = handlerMethod.getMethodAnnotation(PreAuthorize.class);
        //判断methodAnnotation是否为空，为空则表示controller里面没有权限的注解，直接返回true
        if(methodAnnotation==null){
            return true;
        }
        //有注解就获取里面的路径
        String sn = methodAnnotation.value();
        Employee admin = userInfo.getAdmin();
        //判断type是否是员工
        if(admin.getId()!=null){
           //通过员工的logininfoid加载员工角色和权限
            Set<String> snList=userInfo.getPermissions();
           //如果权限里面不包含有注解的权限，则返回false不能查看
            if(!snList.contains(sn)){
                return false;
            }
        }else {
            return true;
        }
        return true;
    }

    private void resultError(HttpServletResponse response ,String msg) throws IOException {
        //3.1拿不到 登录失效返回错误信息
        PrintWriter writer = response.getWriter();//tomcat
        writer.println("{\"success\":false,\"message\":\""+msg+"\"}");
        writer.flush();
        writer.close();
    }
}